package it.tcm.TeacherClassMate.persistent;

import java.io.FileInputStream;
import java.util.Properties;

import javax.naming.InitialContext;

import org.apache.log4j.Logger;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.context.ManagedSessionContext;


public class HibernateUtil {

	/**
	 * Default constructor.
	 */
	private HibernateUtil() {
	}

	/**
	 * Location of hibernate.cfg.xml file. NOTICE: Location should be on the
	 * classpath as Hibernate uses #resourceAsStream style lookup for its
	 * configuration file. That is place the config file in a Java package - the
	 * default location is the default Java package.<br>
	 * <br>
	 * Examples: <br>
	 * <code>CONFIG_FILE_LOCATION = "/hibernate.conf.xml". 
	 * CONFIG_FILE_LOCATION = "/com/foo/bar/myhiberstuff.conf.xml".</code>
	 */

	private static Logger  log = Logger.getLogger(HibernateUtil.class);
	private static final Configuration cfg = new Configuration();
	private static org.hibernate.SessionFactory sessionFactory;
	private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
      
    
	/**
	 * initialises the configuration if not yet done and returns the current
	 * instance
	 * 
	 * @return
	 */
	public static SessionFactory getSessionFactoryInstance() {
		if (sessionFactory == null)
			initSessionFactory();
		return sessionFactory;
	}

	
	/**
	 * initializes the sessionfactory in a safe way even if more than one thread
	 * tries to build a sessionFactory
	 */
	public static synchronized void initSessionFactory() {
		/*
		 * check again for null because sessionFactory may have been
		 * initialized between the last check and now
		 * 
		 */
		
//		ConfigReader cfgReader = ConfigReader.getInstance();
		if (sessionFactory == null) {
			try {
				 cfg.configure(CONFIG_FILE_LOCATION);
								
				String sessionFactoryJndiName = cfg.getProperty(Environment.SESSION_FACTORY_NAME);
				if (sessionFactoryJndiName != null) {
					cfg.buildSessionFactory();
					log.debug("get a jndi session factory");
					sessionFactory = (SessionFactory) (new InitialContext()).lookup(sessionFactoryJndiName);
				} else{
					log.debug("classic factory");
					sessionFactory = cfg.buildSessionFactory();
				}
			} catch (Exception e) {
				System.err.println("%%%% Error Creating HibernateSessionFactory %%%%");
				e.printStackTrace();
				throw new HibernateException("Could not initialize the Hibernate configuration");
			}
		}
	}
	
	public static void close(){
		if (sessionFactory != null)
			sessionFactory.close();
		sessionFactory = null;
	
	}
	
	public static org.hibernate.Session createNewSession() {
	  getSessionFactoryInstance();
      org.hibernate.classic.Session session = HibernateUtil.sessionFactory.openSession();
      session.setFlushMode(FlushMode.MANUAL);
      ManagedSessionContext.bind(session);
      return (org.hibernate.Session) session;
   }

   /**
    * Start a new Transaction in the given session
    * @param session The session to create the transaction in
    */
	public static void startNewTransaction(Session session) {
      session.beginTransaction();
   }

   /**
    * Shortcut method that creates a new session and begins a transaction in it
    * @return A new session with a transaction started
    */
   public static org.hibernate.Session createNewSessionAndTransaction() {
      Session session = createNewSession();
      startNewTransaction(session);
      return session;
   }

   /**
    * Commit the transaction within the given session. This method unbinds
    * the session from the session context (ManagedSessionContext), flushes
    * the session, commmits the session and then closes the session
    * @param session The session with the transaction to commit
    */
   public static void commitTransactionAndCloseSession(Session session) {
      ManagedSessionContext.unbind(HibernateUtil.sessionFactory);
      session.flush();
      session.getTransaction().commit();
      session.close();
   }
   

   /**
    * Commit the transaction within the given session. This method unbinds
    * the session from the session context (ManagedSessionContext), flushes
    * the session, commmits the session and then closes the session
    * @param session The session with the transaction to commit
    */
   public static void commitTransaction(Session session) {
      ManagedSessionContext.unbind(HibernateUtil.sessionFactory);
      session.flush();
      session.getTransaction().commit();
   }
   
   public static void rollbackTransaction(Session session) {
	      ManagedSessionContext.unbind(HibernateUtil.sessionFactory);
	      session.flush();
	      session.getTransaction().rollback();
	      session.close();
	   }

}

